﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Drawing;
using TTServer.Messages;
using TTServer.Utilities;
using libUtilities;
using System.Windows.Forms;

namespace TTServer
{
    public class ScreenshotBroadcastWithoutFeedback
    {
        private static ScreenshotBroadcastWithoutFeedback _instance;

        public static ScreenshotBroadcastWithoutFeedback GetInstance()
        {
            try
            {
                if (_instance == null)
                {
                    _instance = new ScreenshotBroadcastWithoutFeedback();
                }

                return _instance;
            }
            catch
            {
                return null;
            }
        }

        public static void TryToStart()
        {
            ScreenshotBroadcastWithoutFeedback bss = ScreenshotBroadcastWithoutFeedback.GetInstance();

            if (bss != null)
            {
                bss.Start();
            }
        }

        public static void TryToStop()
        {
            ScreenshotBroadcastWithoutFeedback bss = ScreenshotBroadcastWithoutFeedback.GetInstance();

            if (bss != null)
            {
                bss.Stop();
            }
        }
         

        private static int HEADER_SIZE = 8;
        private static int MAX_DATA_SIZE = 65499;
        private static int MAX_PACKETS = 50;
        private static int SESSION_START = 128;
        private static int SESSION_END = 64;
        private static int MAX_SESSION_NUMBER = 7200;

        private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
        private ManualResetEvent _pauseEvent    = new ManualResetEvent(true);

        private Thread _thread = null;

        private bool _bStoped = false;

        private bool _bFirst = true;

        public ScreenshotBroadcastWithoutFeedback()
        {
            ThreadStart threadStart = new ThreadStart(Run);
            _thread = new Thread(threadStart);
            _thread.IsBackground = true;

            _shutdownEvent = new ManualResetEvent(false);
            _pauseEvent = new ManualResetEvent(true);
        }

        public void Start()
        {
            if (_bFirst)
            {
                _thread.Start();
                _bFirst = false;
                return;
            }
            else if (_bStoped)
            {
                ThreadStart threadStart = new ThreadStart(Run);
                _thread = new Thread(threadStart);
                _thread.IsBackground = true;
                _thread.Start();

                _shutdownEvent = new ManualResetEvent(false);
                _pauseEvent = new ManualResetEvent(true);

                _bStoped = false;

                return;
            }
            else {
                Stop();

                ThreadStart threadStart = new ThreadStart(Run);
                _thread = new Thread(threadStart);
                _thread.IsBackground = true;
                _thread.Start();

                _shutdownEvent = new ManualResetEvent(false);
                _pauseEvent = new ManualResetEvent(true);

                _bStoped = false;
            }
        }

        public void Pause()
        {
            _pauseEvent.Reset();
        }

        public void Resume()
        {
            _pauseEvent.Set();
        }

        public void Stop()
        {
            if (_bStoped == false)
            {
                // Signal the shutdown event
                _shutdownEvent.Set();

                // Make sure to resume any paused threads
                _pauseEvent.Set();

                // Wait for the thread to exit
                _thread.Join();

                _bStoped = true;
            }
        }

        private Bitmap CaptureScreen()
        {
            Size size = new Size(Screen.PrimaryScreen.Bounds.Width,
                Screen.PrimaryScreen.Bounds.Height);

            Bitmap bitmap = new Bitmap(size.Width, size.Height);

            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.CopyFromScreen(new Point(0, 0), new Point(0, 0), size);
            }

            return bitmap;
        }

        public byte[] getImageByteArrayFromSlideShowView()
        {
            var img = this.CaptureScreen();

            if (img == null)
                return null;

            var smallImg = ImageUtils.resizeImage(img, new Size(img.Width / 2, img.Height / 2));

            using (var ms = new System.IO.MemoryStream())
            {
                smallImg.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                return ms.ToArray();
            }
        }

        public void Run()
        {
            Socket sock = new Socket(AddressFamily.InterNetwork,
                    SocketType.Dgram, ProtocolType.Udp);

            sock.SetSocketOption(SocketOptionLevel.Socket,
                       SocketOptionName.Broadcast, 1);

            IPEndPoint iep = new IPEndPoint(IPAddress.Broadcast, 11111);

            byte[] imageByteArray = null;

            int sessionNumber = 0;

            try
            {
                while (true)
                {
                    _pauseEvent.WaitOne(Timeout.Infinite);

                    if (_shutdownEvent.WaitOne(0))
                        break;

                    imageByteArray = getImageByteArrayFromSlideShowView();

                    if (imageByteArray != null)
                    {
                        // Calculate the number of packets to be sent in the current session.
                        int a = imageByteArray.Length / MAX_DATA_SIZE;
                        int b = (imageByteArray.Length % MAX_DATA_SIZE) > 0 ? 1 : 0;
                        int i_packets = a + b;

                        if (i_packets > MAX_PACKETS)
                        {
                            throw (new Exception("packets > MAX_PACKETS"));
                        }

                        for (int i = 0; i < i_packets; i++)
                        {
                            int flags = 0;
                            flags = (i == 0) ? (flags | SESSION_START) : flags;
                            flags = (i == (i_packets - 1)) ? (flags | SESSION_END) : flags;

                            int size = ((flags & SESSION_END) != SESSION_END)
                                ? MAX_DATA_SIZE
                                : imageByteArray.Length - i * MAX_DATA_SIZE;

                            byte[] data = new byte[HEADER_SIZE + size];
                            data[0] = (byte)flags;
                            data[1] = (byte)sessionNumber;
                            data[2] = (byte)i_packets;
                            data[3] = (byte)(MAX_DATA_SIZE >> 8);
                            data[4] = (byte)MAX_DATA_SIZE;
                            data[5] = (byte)i;
                            data[6] = (byte)(size >> 8);
                            data[7] = (byte)size;

                            Array.Copy(imageByteArray, i * MAX_DATA_SIZE, data, HEADER_SIZE, size);

                            sock.SendTo(data, iep);

                            Thread.Sleep(300);

                            //if (i != 0)
                            //{
                            //    sock.SendTo(data, iep);

                            //    Thread.Sleep(300);
                            //}
                        }

                        sessionNumber = sessionNumber < MAX_SESSION_NUMBER ? ++sessionNumber : 0;

                    } // if (imageByteArray != null)

                    Thread.Sleep(100);

                } // while (true)
            }
            catch (Exception ex)
            {
                String str = ex.Message;
            }
        }

    }
}
